package com.ag.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 
 * title: DoubleUtils.java 
 * Double 双浮点型数据操作类
 *
 * @author rplees
 * @email rplees.i.ly@gmail.com
 * @version 1.0  
 * @created Mar 6, 2020 11:29:55 AM
 */
public class DoubleUtils {
	
	// 默认除法运算精度
	private static final int DEF_DIV_SCALE = 10;

	/**
	 * 加法运算。
	 * @param v1 被加数
	 * @param v2 加数
	 * @return 两个参数的和
	 */
	public static double add(Object v1, Object v2) {
		return add(v1, v2, 2);
	}
	
	public static double addMulti(Object... array) {
		return addMultiScale(2, array);
	}
	
	public static double addMultiScale(int scale, Object... array) {
		if(array.length == 1) return p(array[0]).doubleValue();
		if(array.length == 2) return add(array[0], array[1], scale);
		BigDecimal temp = p(array[0]).add(p(array[1]));
		
		for (int i = 2; i < array.length; i++) {
			temp = temp.add(p(array[i]));
		}
		
		return temp.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	
	public static double add(Object v1, Object v2, int scale) {
		BigDecimal b1 = p(v1);
		BigDecimal b2 = p(v2);
		return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	
	/**
	 * 浮点数格式化为字符串而没有不必要的小数0
	 * 5.0 -> 5
	 * @param f
	 * @return
	 */
	public static String trimTrailingZeros(Double f) {
		if(f == null) {
			return "0";
		}
		double d = f;
		if (d == (int) d) {
			return String.format("%d", (int) d);
		} else {
			return String.format("%s", d);
		}
	}
	
	/**
	 * 减法运算。
	 * 
	 * @param v1 被减数
	 * @param v2 减数
	 * @return 两个参数的差
	 */
	public static double sub(Object v1, Object v2) {
		return sub(v1, v2, 2);
	}
	
	
	public static double subMulti(Object... array) {
		return subMultiScale(2, array);
	}
	
	public static double subMultiScale(int scale, Object... array) {
		if(array.length == 1) return p(array[0]).doubleValue();
		if(array.length == 2) return sub(array[0], array[1], scale);
		BigDecimal temp = p(array[0]).subtract(p(array[1]));
		
		for (int i = 2; i < array.length; i++) {
			temp = temp.subtract(p(array[i]));
		}
		
		return temp.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	
	public static double sub(Object v1, Object v2, int scale) {
		BigDecimal b1 = p(v1);
		BigDecimal b2 = p(v2);
		return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	public static BigDecimal p(Object o) {
		if (o == null) {
			throw new RuntimeException("cannot be nil.");
		}
		if (o instanceof BigDecimal) {
			return (BigDecimal) o;
		} else if (o instanceof String) {
			return new BigDecimal((String) o);
		} else if (o instanceof Number) {
			if (o instanceof Double) {
				return new BigDecimal(((Double) o));
			} else if (o instanceof Integer) {
				return new BigDecimal(((Integer) o));
			} else if (o instanceof Float) {
				return new BigDecimal(((Float) o));
			}

			return new BigDecimal(((Number) o).doubleValue());
		} else {
			return new BigDecimal(o.toString());
		}
	}
	
	public static double mul(Object v1, Object v2) {
		return mul(v1, v2, 2);
	}
	/**
	 * 乘法运算。
	 * 
	 * @param v1 被乘数
	 * @param v2 乘数
	 * @return 两个参数的积
	 */
	public static double mul(Object v1, Object v2, int scale) {
		BigDecimal b1 = p(v1);
		BigDecimal b2 = p(v2);
		BigDecimal multiply = b1.multiply(b2);
		
		return multiply.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	
	public static double mul(String v1, String v2) {
		return mul(v1, v2, 2);
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后10位，以后的数字四舍五入。
	 * 
	 * @param v1 被除数
	 * @param v2 除数
	 * @return 两个参数的商
	 */
	public static double div(double v1, double v2) {
		return div(v1, v2, DEF_DIV_SCALE);
	}

	/**
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字四舍五入。
	 * 
	 * @param v1 被除数
	 * @param v2 除数
	 * @param scale 表示表示需要精确到小数点以后几位。
	 * @return 两个参数的商
	 */
	public static double div(Object v1, Object v2, int scale) {
		return div(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}
	
	public static double div(String v1, String v2, int scale) {
		return div(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}

	public static double div(Object v1, Object v2, int scale, int round) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b1 = p(v1);
		BigDecimal b2 = p(v2);
		return b1.divide(b2, scale, round).doubleValue();
	}
	
	/**
	 * 小数位四舍五入处理。
	 * @param v
	 * @return 返回两位小数结果
	 * @created 2017年5月4日 下午7:29:22
	 */
	public static double round(double v) {
		return round(v, 2);
	}
	
	public static double round(String v) {
		return round(v, 2);
	}
	
	/**
	 * 小数位四舍五入处理。
	 * 
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static double round(double v, int scale) {
		return round(Double.toString(v), scale);
	}
	
	public static double round(String v, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(v);
		return b.setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
	}
	
	public static Double parse(Object o) {
		if(o == null) {
			throw new IllegalArgumentException("parse o must be not null.");
		}
		
		if(o instanceof Number) {
			return ((Number) o).doubleValue();
		} else if(o instanceof String) {
			return p(o).doubleValue();
		} else {
			return p(o).doubleValue();
		}
	}
}
